package eng.jTrussSolver.Solver;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.crimson.tree.XmlDocument;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import eng.jTrussSolver.Force.ForceHashMap;
import eng.jTrussSolver.Material.MaterialsHashMap;
import eng.jTrussSolver.AssemblerResults.NodeDisplacementHashMap;
import eng.jTrussSolver.AssemblerResults.RodDisplacementHashMap;
import eng.jTrussSolver.Node.NodeHashMap;
import eng.jTrussSolver.Rod.RodHashMap;
import eng.jTrussSolver.Section.SectionHashMap;


//http://java.dzone.com/articles/xml-bindings-jaxb-and-jax-rs 
@XmlRootElement 
public class truss2dProblemDef {
	@XmlElement 
	@XmlElementWrapper(name = "Nodes")  
	private NodeHashMap nodes;
	@XmlElement 
	@XmlElementWrapper(name = "RodList") 
	private RodHashMap rods;
	@XmlElement 
	@XmlElementWrapper(name = "SectionList") 
	private SectionHashMap sections;
	@XmlElement 
	@XmlElementWrapper(name = "MaterialList") 
	private MaterialsHashMap materials;
	@XmlElement
	@XmlElementWrapper(name = "ForcesList")
	private ForceHashMap forces;
	private NodeDisplacementHashMap nodeDisplacements;
	private RodDisplacementHashMap rodDisplacements;



	/**
	 * Constructor. 
	 * instantiates objects and,
	 * sets nodes, rods, materials and Section counters to Zero.
	 */
	public truss2dProblemDef()
	{
		this.rods = new RodHashMap();
		this.nodes = new NodeHashMap();
		this.sections = new SectionHashMap();
		this.materials = new MaterialsHashMap();
		this.forces = new ForceHashMap();
		this.nodeDisplacements = new NodeDisplacementHashMap();
		this.rodDisplacements = new RodDisplacementHashMap();
		
	}

	/**
	 * Constructor. 
	 * assigns values to objects and,
	 * sets nodes, rods, materials and Section counters to Zero.
	 */
	public truss2dProblemDef(NodeHashMap nodes, 
			RodHashMap rods, 
			SectionHashMap sections, 
			MaterialsHashMap materials,
			ForceHashMap  forces,
			NodeDisplacementHashMap nodeDisplacements,
			RodDisplacementHashMap rodDisplacements )
	{
		this.rods = rods;
		this.nodes = nodes;
		this.sections = sections;
		this.materials = materials;
		this.forces = forces;
		this.nodeDisplacements = nodeDisplacements;
		this.rodDisplacements = rodDisplacements;

		//TODO: The counters here are not correctly set. 
		// The counters should be equal at least with the highest number
		// of the highest NODEID in the problem definition.
		//_nodeCounter=0;
		//_RodCounter=0;
		//_forcecounter = 0;
	}
	
	public RodDisplacementHashMap getRodDisplacements() {
		return this.rodDisplacements;
		
	}
	
	public NodeDisplacementHashMap getNodeDisplacements() {
		return this.nodeDisplacements;
	}

	public MaterialsHashMap getMaterials()
	{
		return this.materials;
	}


	/**
	 * returns the Section Collection
	 * @return ArrayList<SectionData> 
	 */
	public SectionHashMap getSections() {
		return this.sections;
	}

	/**
	 * returns the Node Collection
	 * @return NodeHashMap
	 */
	public NodeHashMap getNodes() {
		return nodes;
	}

	
	
	public ForceHashMap getForces() {
		return this.forces;
	}


	/**
	 * returns the Rod Collection
	 * @return 
	 */
	public RodHashMap getRods() {
		return rods;
	}
	

	/**
	 * Function for creating XML file - all data.
	 */
	public void CreateDataXML(String xmlFilename) {

		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db=null;
		XmlDocument xmlData;
		try {
			db = dbf.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		Document doc = db.newDocument();

		Element root = doc.createElement("FinalData_List");
		doc.appendChild(root);
		Element N = this.getNodes().prepareXMLElement(doc, nodes);
		Element S = this.getSections().prepareXMLElement(doc);
		Element M = this.getMaterials().prepareXMLElement(doc);
		Element F = this.getForces().prepareXMLElement(doc);
		Element rodXML = this.getRods().prepareXMLelement(doc, rods);
		// Append to root element
		root.appendChild(N);
		root.appendChild(S);
		root.appendChild(M);
		root.appendChild(F);
		root.appendChild(rodXML);

		xmlData = (XmlDocument) doc;

		try {
			xmlData.write(new FileWriter(xmlFilename), "UTF-8");
		}
		catch (IOException e) {
			e.printStackTrace();
		}

	}



	/**
	 * Creates Xml data file with the use of JAXB
	 * @param filename
	 */

	public void createDataXMLJAXB(String filename)
	{
		truss2dProblemDef nikos = new truss2dProblemDef(nodes, rods, sections, materials, forces, nodeDisplacements, rodDisplacements);
		// create JAXB context and instantiate marshaller
		JAXBContext context;
		Writer w = null;
		try {
			context = JAXBContext.newInstance(truss2dProblemDef.class);
			Marshaller m = context.createMarshaller();
			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			m.marshal(nikos, System.out);

			w = new FileWriter(filename);
			m.marshal(nikos, w);
		} catch (Exception e1) {
			e1.printStackTrace();
		} finally {
			try {
				w.close();
			} catch (Exception e) {
			}
		}
	}

	public void clearProblem() {

		this.rods.clear();
		this.nodes.clear();
		this.materials.clear();
		this.sections.clear();
		this.forces.clear();
		this.nodeDisplacements.clear();
		this.rodDisplacements.clear();
	}
}
